#include <iostream>
#include <memory>
#include <utility>
#include <vector>
template <typename T>
void Print(T t) { std::cout << t << std::endl; }

// 泛型lambda，支持参数传递auto类型，c++14才支持
auto func = [](auto a, auto b)
{ return a + b; };

// 允许捕获列表中创建新变量并初始化，适用于捕获非拷贝的类型或者移动对象
auto p = std::make_unique<int>(10);
auto func1 = [ptr = std::move(p)]()
{
    Print(*ptr);
};

// 使用auto推断返回值类型，C++11允许但是末尾必须指定->returntype, 不好用，c++14没有了这个限制
// 但是多条返回语句必须要推导出相同的类型
auto add(int x, int y)
{
    return x + y;
}
// 适用于完美转发类型
decltype(auto) ff1()
{
    return 0;
}
constexpr int factorial(int n)
{
    int res1 = 10;
    for (int i = 0; i < 10; ++i)
    {
        res1 *= i;
    }
    return res1;
}
// c++14可以计算
constexpr int val = factorial(2);

// 使用'作为数字字面量的分隔符，提高可读性，编译器会忽略它
double x = 3.141'5926;
long long x1 = 432'423'432'423;

// 二进制字面量，之前不能直接写一个二进制数字
int mask = 0b10101010;
int mask1 = 0B10101010;

// 这个特性的名字叫：C++属性
/**
 * C++11引入的有
 *    [[noreturn]]，表示此函数不会返回，让编译器检查时不要warning
 *    [[carries_dependency]]，作用域多线程编程，这个要写在某个参数后边
 */

/**
 * C++14引入的
 * [[deprecated("请改用New Function()")]]
 */
/**
 * C++17引入的
 *  [[fallthrough]]，放在switch-case的末尾，我本意是接着向下传递，编译期可能会警告，
 *  为了避免警告
 *  switch (){
 *      case ... :
 *      case .. :
 *          func();
 *          [[fallthrough]]
 *      case .
 * }
 * [[nodiscard]] 警告不要丢掉该函数的返回值，必须得有一个变量来接受返回值
 * [[maybe_unused]] 告诉编译器不要对未使用的变量发出警告，放在参数前
 *
 */
// [[deprecated("请改用New Function()")]]
void oldFunction()
{
}

void use()
{
    oldFunction();
}

int test()
{
    int a = 10, b = 20;
    return std::exchange(a, b);
}

// 变量模板
template <typename T>
constexpr T pi = T(3.1415926);

template <typename T>
T cular(T r)
{
    return pi<T> * r * r;
}

template <std::size_t N>
constexpr std::size_t fac = N * fac<N - 1>;

template <>
constexpr std::size_t fac<0> = 1;

// C++20支持的写法
auto glambda = []<class T>(T a, auto b)
{ return a < b; };

int main()
{
    // int ret = func(1, 2);
    // double ret1 = func(1, 2.4);
    // Print<int>(ret);
    // Print<double>(ret1);

    // func1();
    // if (!p)
    //     Print("p is nullptr");
    // Print(x);
    // Print(x1);
    // Print(mask);
    // Print(mask1);
    // Print(test());
    Print(cular<double>(10));
    Print(fac<10>);
    // C++20支持的写法
    std::vector<std::string> v;
    auto f2 = [&v]<typename... Args>(Args &&...ts)
    {
        v.emplace_back(std::forward<Args>(ts)...);
    };
    std::string s1("hello world");
    f2(s1);
    f2("111111111");
    f2(10, 'y');
    for (std::string &str : v)
        Print(str);
    return 0;
}